

#include <avr/io.h>
#include <util/delay.h>

/* ATMEGA16 SPI configuration */
#define SPI_SS   PB4
#define SPI_MOSI PB5
#define SPI_MISO PB6
#define SPI_SCK  PB7
#define SPI_DDR  DDRB
#define SPI_PORT PORTB

/* 
 * proper communication is checked by synchronuous 
 * flashing leds on the master and slave 
 */
#define DEBUG_DDR  DDRD
#define DEBUG_PORT PORTD
#define DEBUG_LED  PB6

void debug_led_init(void)
{
	/* set the pin connected to the LED as output */
	DEBUG_DDR = _BV(DEBUG_LED);
}

void debug_led_on(void)
{
	DEBUG_PORT |= _BV(DEBUG_LED);
}

void debug_led_off(void)
{
	DEBUG_PORT &= ~(_BV(DEBUG_LED));
}

void spi_master_init(void)
{
	/* Set MOSI, SCK  and SS output, all others input.
	 * IMPORTANT: SS must be set as output on MASTER to
	 * prevent the master from switching to slave state.
	 */
	SPI_DDR = _BV(SPI_MOSI)|_BV(SPI_SCK)|_BV(SPI_SS);
	/* Enable SPI, Master, set clock rate fck/16 */
	SPCR = _BV(SPE)|_BV(MSTR)|_BV(SPR0);

	/* set SS to HIGH => the slave is not 
	   selected for data transfers */
	SPI_PORT |= _BV(SPI_SS);
}

/*
 * Before transmitting any bytes the master chip 
 * must select the destination slave.
 * Slave selection is done by setting the slave's
 * SS pin to LOW.
 */
void spi_master_begin_transmission()
{
	SPI_PORT &= ~_BV(SPI_SS);
}

void spi_master_transmit(char data)
{
	/* start transmission */
	SPDR = data;
	/* wait for transmission complete */
	while(! (SPSR & (1<<SPIF)))
		;
}

/*
 * After transmitting data, the master chip will tell the 
 * destination slave it finished.
 * The slave is unselected by putting it's SS pin to HIGH.
 */
void spi_master_end_transmission()
{
	SPI_PORT |= _BV(SPI_SS);
}


int main(void)
{
	/* boolean flag: is the debug led on? */
	char led_on = 0;
	
	debug_led_init();
	spi_master_init();

	for(;;)
	{
		led_on = !led_on;
		if (led_on)
			debug_led_on();
		else
			debug_led_off();


		spi_master_begin_transmission();
		spi_master_transmit(led_on);
		/* here we can call spi_master_transmit()
		   multiple times to transmit more than one byte. */
		spi_master_end_transmission();
	
		/* the delay is not needed by SPI but by us
		   to see the leds flashing */
		_delay_ms(5000);
	}
}
